package setting

import (
	"fmt"
	"log"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/go-ini/ini"
)

var (
	Cfg *ini.File

	KConfRoot string

	RunMode string

	HTTPPort     int
	ReadTimeout  time.Duration
	WriteTimeout time.Duration

	PageSize    int
	JwtSecret   string
	JwtLifetime int

	RedisHost     string
	RedisPort     string
	RedisPassword string
	RedisDB       int

	SshPrivateFile string

	NginxTemplate   string
	NginxHost       string
	NginxPort       string
	NginxName       string
	NginxDomainName string

	DockerManagerHost       string
	DockerManagerPort       string
	DockerManagerUser       string
	DockerManagerAuthKey    string
	DockerRepo              string
	DockerPostgresImage     string
	DockerRedisImage        string
	DockerVolumeRoot        string
	DockerBuildResourceRoot string
	DockerKnownHosts        string

	JenkinsCustomerScriptTemplate           string
	JenkinsCustomerJobTemplate              string
	JenkinsBackendScriptTemplate            string
	JenkinsBackendJobTemplate               string
	JenkinsAdminScriptTemplate              string
	JenkinsAdminJobTemplate                 string
	JenkinsMobileScriptTemplate             string
	JenkinsMobileJobTemplate                string
	JenkinsDBScriptTemplate                 string
	JenkinsDBJobTemplate                    string
	JenkinsViewCreateTemplate               string
	JenkinsApplicationRestartJobTemplate    string
	JenkinsApplicationRestartScriptTemplate string
	JenkinsUser                             string
	JenkinsPassword                         string
	JenkinsApiBase                          string

	InstanceCustomerGit           string
	CustomerNginxTemplate         string
	InstanceMobileGit             string
	InstanceBackendGit            string
	InstanceAdminGit              string
	AdminNginxTemplate            string
	InstanceDBName                string
	InstanceDBUser                string
	InstanceDBPassword            string
	InstanceDBKhost               string
	InstanceRedisKhost            string
	InstanceRedisPassword         string
	InstanceCustomerPortRangeLow  int
	InstanceCustomerPortRangeHigh int
	InstanceAdminPortRangeLow     int
	InstanceAdminPortRangeHigh    int
	InstanceMobilePortRangeLow    int
	InstanceMobilePortRangeHigh   int
	InstanceDBPortRangeLow        int
	InstanceDBPortRangeHigh       int
	InstanceRedisPortRangeLow     int
	InstanceRedisPortRangeHigh    int

	CustomerJobSuffix           string
	BackendJobSuffix            string
	AdminJobSuffix              string
	MobileJobSuffix             string
	CeleryJobSuffix             string
	DBJobSuffix                 string
	RedisJobSuffix              string
	InstanceNetworkSuffix       string
	ApplicationRestartJobSuffix string

	InstanceDomainName string
	InstanceAccessIP   string

	ConfTemplateEditLockTimeout time.Duration
)

func init() {
	var err error
	KConfRoot = os.Getenv("K_CONF_ROOT")
	if KConfRoot == "" {
		log.Fatalf("Need env variable 'K_CONF_ROOT' to be set as project root")
	}
	Cfg, err = ini.Load(fmt.Sprintf("%s/conf/app.ini", KConfRoot))
	if err != nil {
		log.Fatalf("Fail to parase 'conf/app.ini': %v", err)
	}

	LoadBase()
	LoadServer()
	LoadApp()
	LoadRedis()
	LoadNginx()
	LoadSsh()
	LoadDockerNode()
	LoadJenkins()
	LoadInstance()
	LoadConfTemplate()
}

func LoadBase() {
	RunMode = Cfg.Section("").Key("RUN_MODE").MustString("debug")
}

func LoadServer() {
	sec, err := Cfg.GetSection("server")
	if err != nil {
		log.Fatalf("Fail to get section 'server': %v", err)
	}

	HTTPPort = sec.Key("HTTP_PORT").MustInt(8000)
	ReadTimeout = time.Duration(sec.Key("READ_TIMEOUT").MustInt(60)) * time.Second
	ReadTimeout = time.Duration(sec.Key("WRITE_TIMEOUT").MustInt(60)) * time.Second
}

func LoadApp() {
	sec, err := Cfg.GetSection("app")
	if err != nil {
		log.Fatalf("Fait to get section 'app': %v", err)
	}

	JwtSecret = sec.Key("JWT_SECRET").MustString("!@(^83!kd%&#(#9")
	JwtLifetime = sec.Key("JWT_LIFETIME").MustInt(120)
	PageSize = sec.Key("PAGE_SIZE").MustInt(10)
}

func LoadRedis() {
	sec, err := Cfg.GetSection("redis")
	if err != nil {
		log.Fatalf("Fail to get section 'redis': %v", err)
	}

	RedisHost = sec.Key("HOST").MustString("127.0.0.1")
	RedisPort = sec.Key("PORT").MustString("6379")
	RedisDB = sec.Key("DB").MustInt(0)
	RedisPassword = sec.Key("PASSWORD").MustString("")
}

func LoadSsh() {
	sec, err := Cfg.GetSection("SshClient")
	if err != nil {
		log.Fatalf("Fail to get section 'SshClient': %v", err)
	}

	SshPrivateFile = sec.Key("PrivateKey").MustString("")
}

func LoadNginx() {
	sec, err := Cfg.GetSection("NginxMachine")
	if err != nil {
		log.Fatalf("Fail to get section 'NginxMachine': %v", err)
	}

	NginxTemplate = sec.Key("Template").MustString("")
	NginxHost = sec.Key("Host").MustString("")
	NginxName = sec.Key("Name").MustString("")
	NginxPort = sec.Key("Port").MustString("")
	NginxDomainName = sec.Key("DomainName").MustString("")
	if NginxTemplate == "" || NginxHost == "" || NginxName == "" || NginxPort == "" || NginxDomainName == "" {
		log.Panic("make sure NginxTemplate, NginxHost, NginxName, NginxPort DomainName all be set")
	}
	NginxTemplate = KConfRoot + "/" + NginxTemplate
}

func LoadDockerNode() {
	sec, err := Cfg.GetSection("Docker")
	if err != nil {
		log.Fatalf("Fail to get section 'DockerNode': %v", err)
	}

	DockerManagerHost = sec.Key("ManagerHost").MustString("")
	DockerManagerPort = sec.Key("ManagerPort").MustString("")
	DockerManagerUser = sec.Key("ManagerUser").MustString("")
	DockerManagerAuthKey = sec.Key("ManagerAuthKey").MustString("")
	DockerRepo = sec.Key("Repository").MustString("")
	DockerPostgresImage = sec.Key("PostgresImage").MustString("")
	DockerRedisImage = sec.Key("RedisImage").MustString("")
	DockerVolumeRoot = sec.Key("VolumeRoot").MustString("")
	DockerBuildResourceRoot = sec.Key("BuildResourceRoot").MustString("")
	DockerKnownHosts = sec.Key("KnownHosts").MustString("")
}

func LoadJenkins() {
	sec, err := Cfg.GetSection("Jenkins")
	if err != nil {
		log.Fatalf("Fail to get section 'Jenkins': %v", err)
	}

	JenkinsCustomerScriptTemplate = KConfRoot + "/" + sec.Key("CustomerScriptTemplate").MustString("")
	JenkinsCustomerJobTemplate = KConfRoot + "/" + sec.Key("CustomerJobTemplate").MustString("")

	JenkinsAdminScriptTemplate = KConfRoot + "/" + sec.Key("AdminScriptTemplate").MustString("")
	JenkinsAdminJobTemplate = KConfRoot + "/" + sec.Key("AdminJobTemplate").MustString("")

	JenkinsMobileScriptTemplate = KConfRoot + "/" + sec.Key("MobileScriptTemplate").MustString("")
	JenkinsMobileJobTemplate = KConfRoot + "/" + sec.Key("MobileJobTemplate").MustString("")

	JenkinsDBScriptTemplate = KConfRoot + "/" + sec.Key("DBScriptTemplate").MustString("")
	JenkinsDBJobTemplate = KConfRoot + "/" + sec.Key("DBJobTemplate").MustString("")

	JenkinsBackendScriptTemplate = KConfRoot + "/" + sec.Key("BackendScriptTemplate").MustString("")
	JenkinsBackendJobTemplate = KConfRoot + "/" + sec.Key("BackendJobTemplate").MustString("")
	JenkinsViewCreateTemplate = KConfRoot + "/" + sec.Key("ViewCreateTemplate").MustString("")

	JenkinsApplicationRestartScriptTemplate = KConfRoot + "/" + sec.Key("ApplicationRestartScriptTemplate").MustString("")
	JenkinsApplicationRestartJobTemplate = KConfRoot + "/" + sec.Key("ApplicationRestartJobTemplate").MustString("")

	JenkinsApiBase = sec.Key("ApiBase").MustString("")
	JenkinsUser = sec.Key("User").MustString("")
	JenkinsPassword = sec.Key("Password").MustString("")
}

func LoadInstance() {
	sec, err := Cfg.GetSection("Instance")
	if err != nil {
		log.Fatalf("Fail to get sect 'Instance': %v", err)
	}

	InstanceCustomerGit = sec.Key("CustomerGit").MustString("")
	InstanceMobileGit = sec.Key("MobileGit").MustString("")
	InstanceAdminGit = sec.Key("AdminGit").MustString("")
	InstanceBackendGit = sec.Key("BackendGit").MustString("")
	InstanceDBName = sec.Key("DBName").MustString("")
	InstanceDBUser = sec.Key("DBUser").MustString("")
	InstanceDBPassword = sec.Key("DBPassword").MustString("")
	InstanceRedisPassword = sec.Key("RedisPassword").MustString("")
	InstanceDomainName = sec.Key("DomainName").MustString("")
	CustomerJobSuffix = sec.Key("CustomerJobSuffix").MustString("")
	AdminJobSuffix = sec.Key("AdminJobSuffix").MustString("")
	BackendJobSuffix = sec.Key("BackendJobSuffix").MustString("")
	CeleryJobSuffix = sec.Key("CeleryJobSuffix").MustString("")
	MobileJobSuffix = sec.Key("MobileJobSuffix").MustString("")
	DBJobSuffix = sec.Key("DBJobSuffix").MustString("")
	RedisJobSuffix = sec.Key("RedisJobSuffix").MustString("")
	InstanceAccessIP = sec.Key("AccessIP").MustString("")
	InstanceNetworkSuffix = sec.Key("NetworkSuffix").MustString("")
	CustomerNginxTemplate = KConfRoot + "/" + sec.Key("CustomerNginxTemplate").MustString("")
	AdminNginxTemplate = KConfRoot + "/" + sec.Key("AdminNginxTemplate").MustString("")
	InstanceDBKhost = sec.Key("DBKhost").MustString("")
	InstanceRedisKhost = sec.Key("RedisKhost").MustString("")
	ApplicationRestartJobSuffix = sec.Key("ApplicationRestartJobSuffix").MustString("")

	customerPortRange := strings.Split(sec.Key("CustomerPortRange").MustString(""), "-")
	InstanceCustomerPortRangeLow, err = strconv.Atoi(customerPortRange[0])
	if err != nil {
		log.Fatalf("Fail to get Instance Customer Port Range: %v", err)
	}
	InstanceCustomerPortRangeHigh, err = strconv.Atoi(customerPortRange[1])
	if err != nil {
		log.Fatalf("Fail to get Instance Customer Port Range: %v", err)
	}

	adminPortRange := strings.Split(sec.Key("AdminPortRange").MustString(""), "-")
	InstanceAdminPortRangeLow, err = strconv.Atoi(adminPortRange[0])
	if err != nil {
		log.Fatalf("Fail to get Instance Admin Port Range: %v", err)
	}
	InstanceAdminPortRangeHigh, err = strconv.Atoi(adminPortRange[1])
	if err != nil {
		log.Fatalf("Fail to get Instance Admin Port Range: %v", err)
	}

	mobilePortRange := strings.Split(sec.Key("MobilePortRange").MustString(""), "-")
	InstanceMobilePortRangeLow, err = strconv.Atoi(mobilePortRange[0])
	if err != nil {
		log.Fatalf("Fail to get Instance Mobile Port Range: %v", err)
	}
	InstanceMobilePortRangeHigh, err = strconv.Atoi(mobilePortRange[1])
	if err != nil {
		log.Fatalf("Fail to get Instance Mobile Port Range: %v", err)
	}

	dbPortRange := strings.Split(sec.Key("DBPortRange").MustString(""), "-")
	InstanceDBPortRangeLow, err = strconv.Atoi(dbPortRange[0])
	if err != nil {
		log.Fatalf("Fail to get Instance DB Port Range: %v", err)
	}
	InstanceDBPortRangeHigh, err = strconv.Atoi(dbPortRange[1])
	if err != nil {
		log.Fatalf("Fail to get Instance DB Port Range: %v", err)
	}

	redisPortRange := strings.Split(sec.Key("RedisPortRange").MustString(""), "-")
	InstanceRedisPortRangeLow, err = strconv.Atoi(redisPortRange[0])
	if err != nil {
		log.Fatalf("Fail to get Instance Redis Port Range: %v", err)
	}
	InstanceRedisPortRangeHigh, err = strconv.Atoi(redisPortRange[1])
	if err != nil {
		log.Fatalf("Fail to get Instance Redis Port Range: %v", err)
	}
}

func LoadConfTemplate() {
	sec, err := Cfg.GetSection("ConfTemplate")
	if err != nil {
		log.Fatalf("Fail to get sect 'ConfTemplate': %v", err)
	}
	ConfTemplateEditLockTimeout = time.Duration(sec.Key("EditLockTimeout").MustInt64(0))
}
